import {pauseTracking, resumeTracking, track, trigger} from './effect.js'
import {hasChanged, isObject} from "./utils.js";
import {reactive} from "./reactive.js";
import {TrackOpTypes, TriggerOpTypes} from "./operations.js";

const arrayInstrumentation = {};
const RAW = Symbol('raw');

['includes', 'indexOf', 'lastIndexOf'].forEach((key) => {
    arrayInstrumentation[key] = function (...args) {
        // this --> proxy
        // 1. 正常找
       const res = Array.prototype[key].apply(this, args)

        // 2. 找不到 从原始对象中重新找一遍
        if (res < 0 || res === false) {
           return Array.prototype[key].apply(this[RAW], args)
        }
        return res;
    }
});
['push', 'pop', 'shift', 'unshift', 'splice'].forEach((key) => {
    arrayInstrumentation[key] = function (...args) {
        pauseTracking(); // 暂停依赖收集
        const result = Array.prototype[key].apply(this, args);
        resumeTracking(); // 恢复依赖收集
        return result;
    }
});

function get(target, key, receiver) {
    if (key === RAW) {
        return target;
    }
    // 依赖收集
    track(target, TrackOpTypes.GET, key);
    if (arrayInstrumentation.hasOwnProperty(key) && Array.isArray(target)) {
        return arrayInstrumentation[key];
    }

    // target[key] = target[[GET]](key, target)
    const result = Reflect.get(target, key, receiver)
    if (isObject(result)) {
        return reactive(result)
    }
    return result; // 返回对象的相应属性值
}

function set(target, key, value, receiver) {
    const type = target.hasOwnProperty(key) ? TriggerOpTypes.SET : TriggerOpTypes.ADD;
    const oldValue = target[key];
    const oldLength = Array.isArray(target) ? target.length : undefined
    const result = Reflect.set(target, key, value, receiver)
    if (!result) {
        return result
    }
    const newLength = Array.isArray(target) ? target.length : undefined
    // 派发更新
    if (hasChanged(oldValue, value) || type === TriggerOpTypes.ADD ) {
        trigger(target, type, key)
        if (Array.isArray(target) && newLength !== oldLength) {
            if (key !== 'length') {
                trigger(target, TriggerOpTypes.SET, 'length')
            }else {
                // 找到那些被删除的下标，依次触发派发更新
                for (let i = newLength; i < oldLength; i++) {
                    trigger(target, TriggerOpTypes.DELETE, i.toString())
                }
            }
        }
    }
    return result; // 返回设置结果
}

function deleteProperty(target, key) {
    const hadKey = target.hasOwnProperty(key);
    const result = Reflect.deleteProperty(target, key);
    if (hadKey && result) {
        trigger(target, TriggerOpTypes.DELETE, key);
    }
    return result; // 删除对象的相应属性
}

function has(target, key) {
    track(target, TrackOpTypes.HAS, key);
    return Reflect.has(target, key); // 判断对象是否有相应的属性值
}

function ownKeys(target) {
    // 依赖收集
    track(target, TrackOpTypes.ITERATE);
    return Reflect.ownKeys(target); // 返回对象的所有属性名
}




export const handlers = {
    get,
    set,
    has,
    ownKeys,
    deleteProperty
}
